/*==========================================================================
 *
 *  Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
 *
 *  File:       util.c
 *  Content:    miscellaneous functions
 *
 *
 ***************************************************************************/
#include "util.h"

/*
 * Globals
 */
static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
                                8, 9, '-', 10, 11, 12, 13, 14, 15 };
static const WCHAR wszDigits[] = L"0123456789ABCDEF";


/*
 * StringFromGUID
 * 
 * Converts a GUID into a wide string
 */
int StringFromGUID(LPGUID lpguid, LPWSTR lpwsz)
{
    int i;

    const BYTE * pBytes = (const BYTE *) lpguid;

    *lpwsz++ = L'{';

    for (i = 0; i < sizeof(GuidMap); i++)
    {
        if (GuidMap[i] == '-')
        {
            *lpwsz++ = L'-';
        }
        else
        {
            *lpwsz++ = wszDigits[ (pBytes[GuidMap[i]] & 0xF0) >> 4 ];
            *lpwsz++ = wszDigits[ (pBytes[GuidMap[i]] & 0x0F) ];
        }
    }
    *lpwsz++ = L'}';
    *lpwsz   = L'\0';

    return GUIDSTR_MAX;
}

/*
 * IsEqualGuid
 *
 * Determines if two guids are equal
 */
BOOL  IsEqualGuid(GUID *lpguid1, GUID *lpguid2)
{
   return (
      ((PLONG) lpguid1)[0] == ((PLONG) lpguid2)[0] &&
      ((PLONG) lpguid1)[1] == ((PLONG) lpguid2)[1] &&
      ((PLONG) lpguid1)[2] == ((PLONG) lpguid2)[2] &&
      ((PLONG) lpguid1)[3] == ((PLONG) lpguid2)[3]);
}


// convert a hex char to an int - used by str to guid conversion
// we wrote our own, since the ole one is slow, and requires ole32.dll
// we use ansi strings here, since guids won't get internationalized
int GetDigit(LPSTR lpstr)
{
    char ch = *lpstr;
    
    if (ch >= '0' && ch <= '9')
        return(ch - '0');
    if (ch >= 'a' && ch <= 'f')
        return(ch - 'a' + 10);
    if (ch >= 'A' && ch <= 'F')
        return(ch - 'A' + 10);
    return(0);
}
// walk the string, writing pairs of bytes into the byte stream (guid)
// we need to write the bytes into the byte stream from right to left
// or left to right as indicated by fRightToLeft
void ConvertField(LPBYTE lpByte,LPSTR * ppStr,int iFieldSize,BOOL fRightToLeft)
{
    int i;

    for (i=0;i<iFieldSize ;i++ )
    {
        // don't barf on the field separators
        if ('-' == **ppStr) (*ppStr)++; 
        if (fRightToLeft == TRUE)
        {
            // work from right to left within the byte stream
            *(lpByte + iFieldSize - (i+1)) = 16*GetDigit(*ppStr) + GetDigit((*ppStr)+1);
        } 
        else 
        {
            // work from  left to right within the byte stream
            *(lpByte + i) = 16*GetDigit(*ppStr) + GetDigit((*ppStr)+1);
        }
        *ppStr+=2; // get next two digit pair
    }
} // ConvertField


// convert the passed in string to a real GUID
// walk the guid, setting each byte in the guid to the two digit hex pair in the
// passed string
HRESULT GUIDFromString(LPWSTR lpWStr, GUID * pGuid)
{
    BYTE * lpByte; // byte index into guid
    int iFieldSize; // size of current field we're converting
    // since its a guid, we can do a "brute force" conversion
    char lpTemp[GUID_STRING_SIZE];
    char *lpStr = lpTemp;

    WideToAnsi(lpStr,lpWStr,GUID_STRING_SIZE);
    
    // make sure we have a {xxxx-...} type guid
    if ('{' !=  *lpStr) return E_FAIL;
    lpStr++;
    
    lpByte = (BYTE *)pGuid;
    // data 1
    iFieldSize = sizeof(unsigned long);
    ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
    lpByte += iFieldSize;

    // data 2
    iFieldSize = sizeof(unsigned short);
    ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
    lpByte += iFieldSize;

    // data 3
    iFieldSize = sizeof(unsigned short);
    ConvertField(lpByte,&lpStr,iFieldSize,TRUE);
    lpByte += iFieldSize;

    // data 4
    iFieldSize = 8*sizeof(unsigned char);
    ConvertField(lpByte,&lpStr,iFieldSize,FALSE);
    lpByte += iFieldSize;

    // make sure we ended in the right place
    if ('}' != *lpStr) 
    {
        memset(pGuid,0,sizeof(GUID));
        return E_FAIL;
    }

    return S_OK;
}// GUIDFromString

/*
 ** WideToAnsi
 *
 *  CALLED BY:  everywhere
 *
 *  PARAMETERS: lpStr - destination string
 *              lpWStr - string to convert
 *              cchStr - size of dest buffer
 *
 *  DESCRIPTION:
 *              converts unicode lpWStr to ansi lpStr.
 *              fills in unconvertable chars w/ DPLAY_DEFAULT_CHAR "-"
 *              
 *
 *  RETURNS:  if cchStr is 0, returns the size required to hold the string
 *              otherwise, returns the number of chars converted
 *
 */
int WideToAnsi(LPSTR lpStr,LPWSTR lpWStr,int cchStr)
{

    int rval;
    BOOL bDefault;

    // use the default code page (CP_ACP)
    // -1 indicates WStr must be null terminated
    rval = WideCharToMultiByte(CP_ACP,0,lpWStr,-1,lpStr,cchStr,"-",&bDefault);

    return rval;

} // WideToAnsi

/*
 ** AnsiToWide
 *
 *  CALLED BY: everywhere
 *
 *  PARAMETERS: lpWStr - dest string
 *              lpStr  - string to convert
 *              cchWstr - size of dest buffer
 *
 *  DESCRIPTION: converts Ansi lpStr to Unicode lpWstr
 *
 *
 *  RETURNS:  if cchStr is 0, returns the size required to hold the string
 *              otherwise, returns the number of chars converted
 *
 */
int AnsiToWide(LPWSTR lpWStr,LPSTR lpStr,int cchWStr)
{
    int rval;

    rval =  MultiByteToWideChar(CP_ACP,0,lpStr,-1,lpWStr,cchWStr);

    return rval;
}  // AnsiToWide


/* 
 * randInt
 *
 * returns a random integer in the specified range
 */
int randInt( int low, int high )
{
    int range = high - low;
    int num = rand() % range;
    return( num + low );
}

/*
 * randDouble
 *
 * returns a random double in the specified range
 */
double randDouble( double low, double high )
{
    double range = high - low;
    double num = range * (double)rand()/(double)RAND_MAX;
    return( num + low );
}

